//
// Created by v on 24-5-15.
//

#include <arpa/inet.h>
#include <errno.h>
#include <fcntl.h>
#include <netdb.h>
#include <netinet/in.h>
#include <pthread.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>

#include "cm_broadcast_func.h"

struct CMBroadcast
{
    int       iSockFD;
    int       iPort;
    int       iExit;

    struct sockaddr_in addrto;
};

int cm_broadcast_init(CMBroadcastHandle *h, int port)
{
    struct CMBroadcast *in =
            (struct CMBroadcast *)malloc(sizeof(struct CMBroadcast));
    if (!in)
    {
        return -1;
    }
    memset(in, 0, sizeof(struct CMBroadcast));
    in->iPort = port;
    in->iExit = 0;

    *h = in;
    return 0;
}

int cm_broadcast_set_info(CMBroadcastHandle h, const char *mac, const char *ip,
                          const char *version)
{
    if (!h)
        return -1;
    return 0;
}

int cm_broadcast_socket_init(CMBroadcastHandle h)
{
    if (!h)
        return -1;

    h->iSockFD = socket(AF_INET, SOCK_DGRAM, 0);
    if (h->iSockFD == -1)
    {
        return -2;
    }
    const int opt = 1;
    int nb = setsockopt(h->iSockFD, SOL_SOCKET, SO_BROADCAST, (char *)&opt,
                        sizeof(opt));
    if (nb == -1)
    {
        return -3;
    }
    int flags = fcntl(h->iSockFD, F_GETFL, 0);
    flags |= O_NONBLOCK;
    fcntl(h->iSockFD, F_SETFL, flags);

    memset(&h->addrto, 0, sizeof(h->addrto));
    h->addrto.sin_family      = AF_INET;
    h->addrto.sin_addr.s_addr = htonl(INADDR_BROADCAST);
    h->addrto.sin_port        = htons(h->iPort);

    return 0;
}

int cm_broadcast_socket_init_simple(CMBroadcastHandle h)
{
    return cm_broadcast_socket_init(h);
}

int cm_broadcast_bind(CMBroadcastHandle h)
{
    if (!h)
    {
        return -11;
    }
    if (h->iSockFD <= 0)
    {
        return -22;
    }

    int ret = bind(h->iSockFD, &h->addrto, sizeof(h->addrto));

    return ret;
}

int cm_broadcast_start(CMBroadcastHandle h)
{
    int ret = cm_broadcast_socket_init(h);
    if (ret < 0)
    {
        return ret;
    }

    return 0;
}

int cm_broadcast_close(CMBroadcastHandle *h)
{
    if (h)
    {
        if ((*h)->iSockFD > 0)
        {
            close((*h)->iSockFD);
        }
        free(*h);
    }
    *h = NULL;
    return 0;
}

int cm_broadcast_send(CMBroadcastHandle h, char *data, size_t len)
{
    if (h->iSockFD < 0)
    {
        return -2;
    }

    int ret = sendto(h->iSockFD, data, len, 0,
                     (struct sockaddr *)&h->addrto, sizeof(h->addrto));
    return ret;
}

int cm_broadcast_recv(CMBroadcastHandle h, char *data, size_t len)
{
    if (h->iSockFD <= 0)
    {
        return -2;
    }

    unsigned int sock_len = sizeof(h->addrto);
    int ret = recvfrom(h->iSockFD, data, len, 0,
                       (struct sockaddr *)&h->addrto, &sock_len);
    return ret;
}
